#include "log.hpp"
#include "Socket.hpp"
#include <sys/epoll.h>
class EpollServer
{
using func_t = function<int(int )>;
private:
    int epfd_;
    int listenSock_;
    int port_;
    func_t func_;//处理普通fd的函数，返回读取的字符个数，其实就是封装recv
public:
    static const int gsize = 128; // epoll实例的大小，即能够监视的文件描述符的数量
    static const int num = 128;   // 从就绪队列至多能获取的文件描述符个数
    EpollServer(int port,func_t func) : epfd_(-1),listenSock_(-1), port_(port),func_(func) {}
    ~EpollServer()
    {
        if (listenSock_ != -1)
            close(listenSock_);
        if (epfd_ != -1)
            close(epfd_);
    }

public:
    void InitEpollServer()
    {
        // 1.创建套接字，绑定，监听
        listenSock_ = Sock::Socket();
        Sock::Bind(listenSock_, port_);
        Sock::Listen(listenSock_);
        // 2.创建epoll模型
        epfd_ = epoll_create(gsize);
        if (epfd_ < 0)
        {
            logMessage(FATAL, "%d:%s", errno, strerror(errno));
            exit(1);
        }
        logMessage(DEBUG, "listen :%d success", listenSock_);
        logMessage(DEBUG, "epoll_create :%d success", epfd_);
    }

    void Run()
    {
        // 1.创建listenSock_的epoll结构，然后将其添加到epoll模型
        epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = listenSock_;
        int n = epoll_ctl(epfd_, EPOLL_CTL_ADD, listenSock_, &ev);
        assert(n == 0);
        (void)n;
        // 2.循环检测就绪队列
        epoll_event evs[num];
        int timeout = 1000; // 等待的毫秒数
        while (1)
        {
            int n = epoll_wait(epfd_, evs, num, timeout);
            switch (n)
            {
            case 0:
                cout << "time out ...... " << endl;
                /* code */
                break;
            case -1:
                cerr << errno << ":" << strerror(errno) << endl;
                break;
            default:
                HandlerEvents(evs, n);
                break;
            }
        }
    }
    void HandlerEvents(epoll_event *evs, int n) // 就绪的fd个数
    {
        for (int i = 0; i < n; i++)
        {
            epoll_event &ev = evs[i];
            int sock = ev.data.fd;
            uint32_t revent = ev.events;
            if (revent & EPOLLIN) // 读事件就绪
            {
                if (sock == listenSock_) // 监听套接字就绪
                {
                    // 1.accept
                    string ip;
                    uint16_t port;
                    int sockfd = Sock::Accept(listenSock_, &port, &ip);
                    if (sockfd < 0)
                    {
                        logMessage(FATAL, "%d:%s", errno, strerror(errno));
                        continue;
                    }
                    logMessage(DEBUG, "获取连接成功:ip是%s,port是%d", ip.c_str(), port);
                    // 2.创建epoll结构体，添加到epoll模型
                    epoll_event newEv;
                    newEv.data.fd = sockfd;
                    newEv.events = EPOLLIN;
                    int n = epoll_ctl(epfd_, EPOLL_CTL_ADD, sockfd, &newEv);
                    assert(n == 0);
                    (void)n;
                }
                else // 普通文件描述符
                {
                    int n=func_(sock);
                    if(n<=0)
                    {
                        int x=epoll_ctl(epfd_,EPOLL_CTL_DEL,sock,nullptr);
                        assert(x==0);
                        (void)x;
                        logMessage(DEBUG,"client quit:%d",sock);
                        close(sock);
                    }
                }
            }
        }
    }
};